///结构体
//结构体 (struct) 是一种记录类型，所包含的每个域 (field) 都有一个名称。 每个结构体也都有一个名称，通常以大写字母开头，
// 使用驼峰命名法。 元组结构体 (tuple struct) 是由元组和结构体混合构成，元组结构体有名称， 但是它的域没有。
// 当元组结构体只有一个域时，称为新类型 (newtype)。 没有任何域的结构体，称为类单元结构体 (unit-like struct)。
// 结构体中的值默认是不可变的，需要给结构体加上mut使其可变。

//需要注意，Rust在语言级别不支持域可变性 (field mutability)，所以不能这么写：
//struct Point {
//     mut x: i32,
//     y: i32,
// }

/*结构体struct*/
struct User{
    username: String,
    email: String,
    age: u8,
    active: bool,
}
//空结构体
struct D;
impl D {
    fn get_msg(&self) -> String {
        String::from("empty struct D")
    }
}

#[test]
pub fn test_empty_struct() {
    //直接用结构体名调用方法
    let msg = D.get_msg();
    println!("{}", msg);
}

#[test]
pub fn struct_demo(){
    let user = User{
        username: String::from("admin"),
        email: String::from("someone@example.com"),
        age: 23,
        active: true,
    };
    println!("{}", user.username);

    let user = create_user(String::from("super"),
                           String::from("ok@example.com"));
    println!("{}", user.username);

    let user2 = User{..user};
    println!("{}", user2.username);
}
//返回结构体
fn create_user(username: String, email: String) -> User{
    User{
        username,
        email,
        age: 33,
        active: true
    }
}
//Tuple struct 元组结构体
struct Color(u8, u8, u8);

pub fn tuple_struct_demo(){
    let color = Color(0xfe, 0x33, 0xee);
    println!("{}, {}, {}", color.0, color.1, color.2);
}

/*struct方法*/
struct Rect{
    width: u32,
    height: u32,
}
//给结构体定义方法
impl Rect{
    //求面积的方法
    fn area(&self) -> u32 { //使用引用，不会获取实例的所有权
        self.width * self.height
    }
    fn change_width(&mut self, width: u32){
        self.width = width;
    }
    fn change_height(mut self, height: u32){
        self.height = height; //获取了实例的所有权
    }
    //关联函数（静态方法）
    fn square(size: u32) -> Rect {
        Rect{
            width: size,
            height: size
        }
    }
}

pub fn struct_method_demo(){
    let mut rect = Rect{
        width: 30,
        height: 50,
    };
    let area = rect.area();
    println!("{}", area);

    rect.change_width(80);
    println!("{}", rect.area());
    //rect.change_height(20); //已经把所有权交给了该方法，此后不能再使用rect
    //println!("{}", rect.area());

    rect = Rect::square(50);
    println!("{}", rect.area());
}
#[derive(Debug)]
struct Cat{
    name: String,
}
impl Drop for Cat{
    fn drop(&mut self){
        println!("Drop Cat name={}", self.name);
    }
}
#[derive(Debug)]
struct Student{
    id: i32,
    cat: Cat,
}
impl Drop for Student {
    fn drop(&mut self) {
        println!("Drop Student id={}", self.id);
    }
}
#[test]
pub fn struct_demo2(){
    let mut s = Student{id:1_i32, cat: Cat{name: String::from("大宝")}};
    {
        //指向新的对象
        s.cat = Cat{name: String::from("小白")};
    }//离开作用域，旧的对象cat(大宝)失效 被drop掉
    println!("{:?}", s);

}